package com.cf.invoker.http.client;

import com.cf.invoker.HttpInvokerConstant;
import com.cf.invoker.RemoteClient;
import com.cf.util.ObjectJsonUtil;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Method;
import java.util.*;

/****
 *
 * @Author zhu-mingming
 * @Description
 * @Date 2018/10/23
 *
 **/

public class ClientInvocationHandler implements InvocationHandler {

    private RestTemplate restTemplate;

    private Map<Method, ClientMeta> clientMetaMap = new HashMap<>();

    ClientInvocationHandler(Map<Method, ClientMeta> clientMetaMap, RestTemplate restTemplate) {
        this.clientMetaMap = clientMetaMap;
        this.restTemplate = restTemplate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ClientMeta clientMeta = clientMetaMap.get(method);
        if (clientMeta == null) {
            throw new IllegalArgumentException("为发现Method对应的ClientMeta" + method.getName());
        }
        RemoteClient remoteClient = clientMeta.getRemoteClient();
        return restTemplate.postForObject(createRequestUrl(remoteClient.domain()), formatRequest(method, args), clientMeta.getResponseType());
    }

    private String createRequestUrl(String domain) {
        return domain + HttpInvokerConstant.ROOT_URL;
    }

    private HttpEntity<LinkedMultiValueMap<String, String>> formatRequest(Method method, Object[] args) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.put(HttpInvokerConstant.SERVICR_KEY, Arrays.asList(method.getDeclaringClass().getName() + "." + method.getName()));
        map.put(HttpInvokerConstant.ARGUES, Arrays.asList(serialize(args)));
        HttpEntity<LinkedMultiValueMap<String, String>> request = new HttpEntity<LinkedMultiValueMap<String, String>>(map, headers);
        return request;
    }

    private String serialize(Object[] args) {
        List<String> argsStringList = new LinkedList<String>();
        for (Object arg : args) {
            argsStringList.add(ObjectJsonUtil.toString(arg));
        }
        return ObjectJsonUtil.toString(argsStringList);
    }


}
